package org.finesys.common.redisson.lockResover.impl;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.finesys.common.redisson.annotation.DistributedLock;
import org.finesys.common.redisson.entity.LockEntity;
import org.finesys.common.redisson.lockResover.DistributedLockResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import cn.hutool.core.util.ArrayUtil;

/**
 * spring el表达式key解析器
 */
public class ExpressionDistributedLockKeyResolver implements DistributedLockResolver {
    /**
     * 参数解析器
     */
    private final ExpressionParser expressionParser = new SpelExpressionParser();
    /**
     * 获取方法参数名
     */
    private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();

    @Override
    public LockEntity resolver(ProceedingJoinPoint proceedingJoinPoint, DistributedLock distributedLock) {
        // 获得被拦截方法参数名列表
        Method method = getMethod(proceedingJoinPoint);
        // 获取方法参数
        Object[] args = proceedingJoinPoint.getArgs();
        //获取参数名
        String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method);
        //准备 Spring EL 表达式解析的上下文
        StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        if (ArrayUtil.isNotEmpty(parameterNames)) {
            for (int i = 0; i < parameterNames.length; i++) {
                standardEvaluationContext.setVariable(parameterNames[i], args[i]);
            }
        }
        // 解析参数
        Expression expression = expressionParser.parseExpression(distributedLock.lockName());

        return new LockEntity().setLockName(expression.getValue(standardEvaluationContext, String.class)).setWaitTime(distributedLock.waitTime())
                .setLeaseTime(distributedLock.leaseTime()).setTimeUnit(distributedLock.timeUnit());
    }

    private Method getMethod(ProceedingJoinPoint proceedingJoinPoint) {
        // 处理，声明在类上的情况
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        if (!method.getDeclaringClass().isInterface()) {
            return method;
        }
        // 处理，声明在接口上的情况
        try {
            return proceedingJoinPoint.getTarget().getClass().getDeclaredMethod(proceedingJoinPoint.getSignature().getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
